package com.maple.p2pclient.p2s;

import android.media.MediaCodecInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;

import com.blankj.utilcode.util.GsonUtils;
import com.maple.p2pclient.R;
import com.maple.p2pclient.app.Const;
import com.maple.p2pclient.core.PeerConnectionObserverAdapter;
import com.maple.p2pclient.core.SdpObserverAdapter;
import com.maple.p2pclient.http.RetrofitClient;
import com.maple.p2pclient.http.bean.SrsRequestBean;
import com.maple.p2pclient.http.bean.SrsResponseBean;
import com.maple.p2pclient.socket.SocketType;
import com.maple.p2pclient.ui.MessageAdapter;
import com.maple.p2pclient.utils.LogUtils;
import com.maple.p2pclient.utils.WebRTCUtils;

import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStreamTrack;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RtpTransceiver;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoEncoderSupportedCallback;
import org.webrtc.VideoTrack;

import java.util.ArrayList;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

import static org.webrtc.DefaultVideoEncoderFactoryExtKt.createCustomVideoEncoderFactory;

public class P2SAppActivity extends AppCompatActivity {

    private ListView lvList;
    private Button btnStart;
    private SurfaceViewRenderer remoteRenderer;

    private PeerConnectionFactory peerConnectionFactory;
    private PeerConnection peerConnection;

    private EglBase.Context eglBaseContext = EglBase.create().getEglBaseContext();

    private MessageAdapter listAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_p2s_app);
        lvList = findViewById(R.id.lv_list);
        btnStart = findViewById(R.id.btn_start);
        remoteRenderer = findViewById(R.id.svr_remote_renderer);
        remoteRenderer.init(eglBaseContext,null);
        remoteRenderer.setMirror(false);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                createOffer();
            }
        });

        listAdapter = new MessageAdapter(this,new ArrayList<String>());
        lvList.setAdapter(listAdapter);

        initRTC();
    }

    private void initRTC() {
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        DefaultVideoEncoderFactory encoderFactory = createCustomVideoEncoderFactory(eglBaseContext, true, true, new VideoEncoderSupportedCallback() {
            @Override
            public boolean isSupportedH264(@NonNull MediaCodecInfo info) {
                return true;
            }
        });

        DefaultVideoDecoderFactory decoderFactory = new DefaultVideoDecoderFactory(eglBaseContext);
        peerConnectionFactory = PeerConnectionFactory
                .builder()
                .setOptions(options)
                .setVideoEncoderFactory(encoderFactory)
                .setVideoDecoderFactory(decoderFactory)
                .createPeerConnectionFactory();

        PeerConnection.RTCConfiguration rtcConfig = WebRTCUtils.createRTCConfiguration();
        rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;

        peerConnection = peerConnectionFactory.createPeerConnection(rtcConfig,new PeerConnectionObserverAdapter(SocketType.APP.getType()){

            @Override
            public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
                super.onIceConnectionChange(iceConnectionState);
                LogUtils.logGGQ("app onIceConnectionChange");
            }

            @Override
            public void onIceCandidate(IceCandidate iceCandidate) {
                super.onIceCandidate(iceCandidate);
            }

            @Override
            public void onTrack(RtpTransceiver transceiver) {
                super.onTrack(transceiver);
                // 回调
                if (transceiver != null && transceiver.getReceiver().track() instanceof VideoTrack) {
                    VideoTrack videoTrack = (VideoTrack) transceiver.getReceiver().track();
                    if(videoTrack != null) {
                        videoTrack.addSink(remoteRenderer);
                    }
                }
            }
        });
    }

    private void createOffer() {
        if(peerConnection != null) {
            peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO, new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY));
            peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO,new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY));
            peerConnection.createOffer(new SdpObserverAdapter("createOffer") {
                @Override
                public void onCreateSuccess(SessionDescription sdp) {
                    super.onCreateSuccess(sdp);
                    if(sdp != null && sdp.type == SessionDescription.Type.OFFER) {
                        peerConnection.setLocalDescription(new SdpObserverAdapter("setLocalDescription"),sdp);
                        // 推流端将 offer 发送给 SRS
                        String offerSdp = sdp.description;
                        SrsRequestBean requestBean = new SrsRequestBean();
                        requestBean.sdp = offerSdp;
                        requestBean.streamurl = Const.LIVE_URL;
                        try {
                            RetrofitClient retrofitClient = new RetrofitClient();
                            Call<SrsResponseBean> call = retrofitClient.getApiService(Const.BASE_URL).play(requestBean);
                            LogUtils.logGGQ("url:" + call.request().url());
                            LogUtils.logGGQ("requestBean:" + GsonUtils.toJson(requestBean));

                            call.enqueue(new Callback<SrsResponseBean>() {
                                @Override
                                public void onResponse(@NonNull Call<SrsResponseBean> call, @NonNull Response<SrsResponseBean> response) {
                                    if (response.isSuccessful()) {
                                        SrsResponseBean responseBean = response.body();
                                        LogUtils.logGGQ("responseBean:" + GsonUtils.toJson(responseBean));
                                        if(responseBean != null && responseBean.code == 0) {
                                            LogUtils.logGGQ("publish 请求成功:" + response.code());
                                            String sdp = responseBean.sdp;
                                            SessionDescription remoteSdp = new SessionDescription(SessionDescription.Type.ANSWER, sdp);
                                            peerConnection.setRemoteDescription(new SdpObserverAdapter("setRemoteDescription"), remoteSdp);
                                            addItemList(GsonUtils.toJson(responseBean));
                                        } else {
                                            LogUtils.logGGQ("publish 请求失败1:" + response.code());
                                        }
                                    } else {
                                        LogUtils.logGGQ("publish 请求失败2:" + response.message());
                                    }
                                }

                                @Override
                                public void onFailure(@NonNull Call<SrsResponseBean> call, @NonNull Throwable t) {
                                    LogUtils.logGGQ("publish 请求错误:" + t.getMessage());
                                }
                            });
                        }catch (Exception e) {
                            LogUtils.logGGQ("publish 请求异常:" + e.getMessage());
                        }
                    }
                }
            },new MediaConstraints());

        }
    }

    private void addItemList(String item) {
        listAdapter.addItem(item);
        lvList.smoothScrollToPosition(listAdapter.getDataList().size() - 1);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if(remoteRenderer != null) {
            remoteRenderer.release();
        }
        if(peerConnection != null) {
            peerConnection.dispose();
        }
        if(peerConnectionFactory != null) {
            peerConnectionFactory.dispose();
        }
    }
}